import { AclType } from "@/core/pinia/interface";
import {
  CascaderValue,
  UploadFile,
  UploadFiles,
  UploadRawFile,
  UploadRequestOptions
} from "element-plus";
import { Mark } from "element-plus/es/components/slider/src/composables";
import { Awaitable } from "element-plus/es/utils";
import { Component, CSSProperties } from "vue";
import {
  SFSchemaType,
  NzSafeAny,
  SFBuiltInWidgets,
  SFDLSSize,
  TChange,
  TValidated
} from "./type";
export interface SFGridSizeSchema {
  span?: number | null;
  order?: number | null;
  offset?: number | null;
  push?: number | null;
  pull?: number | null;
}
export interface SFGridSchema {
  /**
   * `label` 栅格占位格数，默认：`5`
   * - `0` 时相当于 `display: none`
   * - 限 `horizontal` 水平布局有效
   */
  spanLabel?: number | null;
  /**
   * 栅格间隔
   */
  gutter?: number | null;
  /**
   * 栅格占位格数，为 `0` 时相当于 `display: none`
   */
  span?: number | null;
  /**
   * 数组索引栅格占位格数，为 `0` 时相当于 `display: none`，限 `type: 'array'` 时有效
   */
  arraySpan?: number | null;
  /**
   * 栅格左侧的间隔格数，间隔内不可以有栅格
   */
  offset?: number | null;
  xs?: number | SFGridSizeSchema;
  sm?: number | SFGridSizeSchema;
  md?: number | SFGridSizeSchema;
  lg?: number | SFGridSizeSchema;
  xl?: number | SFGridSizeSchema;
  xxl?: number | SFGridSizeSchema;
}
export interface ItemsEnum {
  label: string;
  value: string | number | boolean | NzSafeAny;
  disabled?: boolean;
  hidden?: boolean;
}

export interface CheckBoxEnum extends ItemsEnum {
  checked?: boolean;
}

export interface SelectEnum {
  label?: string;
  options?: ItemsEnum[];
}
export interface CascaderEnum {
  label: string;
  value: string | number | boolean | NzSafeAny;
  disabled?: boolean;
  leaf?: boolean;
  children?: CascaderEnum[];
}
export interface SFUISchemaItem<C = (val: NzSafeAny) => void> {
  /**
   * 指定采用什么小部件渲染，所有小部件名可[查阅文档](https://ng-alain.com/)
   */
  widget?: SFBuiltInWidgets | (string & {});

  disabled?: boolean;

  /**
   * 元素组件大小
   */
  size?: SFDLSSize;
  /**
   * 指定宽度，单位：`px`
   */
  width?: number;
  /**
   * 响应式属性
   */
  grid?: SFGridSchema;

  /**
   * 是否隐藏
   */
  hidden?: boolean;

  /**
   * ACL 配置
   */
  acl?: AclType | null;

  placeholder?: string;

  /**custumValid */
  customVaild?: [RegExp, string, string?];
  validate?: TValidated;
  asyncValidate?: (VAL: NzSafeAny) => Promise<boolean>;
  errorMsg?: string;

  /**
   * 预处理函数，可将元数据转为sf 支持的格式
   */
  preFormat?: (data: NzSafeAny) => NzSafeAny;
  /**
   * 预处理函数，可将sf 格式的数据转为实际数据
   */
  nxtFormat?: (data: NzSafeAny) => NzSafeAny;

  /**改变得回调函数 */
  change?: C;

  visibleIf?: {
    [key: string]: (data: NzSafeAny) => boolean;
  };
  visibleModa?: "all" | "one";
}
export interface SFSchema<U = SFUISchemaItem> {
  [key: string]: NzSafeAny;

  /**
   * 常用内容校验
   */
  format?: "mobile" | "idCard" | "email" | "chinese" | "noChinese" | "url";
  /**
   * 数据类型，支持 JavaScript 基础类型；注意项：
   *
   * - `integer` 表示整型，`number` 表示浮点型
   * - JSON 中 `date` 等同 `string` 类型
   * - 指定 `format` 标准参数可以自动适配渲染小部件
   * - 指定 `widget` 参数强制渲染小部件
   */
  type?: SFSchemaType;
  /**
   * 属性描述，相当于 `label` 值，按以下规则展示：
   * - 当值为 `null`、`undefined` 时使用 `key` 替代
   * - 当值为 `''` 空字符串表示不展示 `label` 部分，例如：`checkbox` 可能需要
   */
  title?: string | null;
  /**
   * 是否只读状态
   */
  readonly?: boolean | ((data: NzSafeAny) => boolean);
  /**
   * 默认值
   */
  default?: NzSafeAny;
  /**
   * 必填项属性
   */
  required?: string[];

  /**
   * 是否忽略
   */
  ignore?: boolean;

  /**
   * 是否脱敏，对于敏感数据，在二次更新的时候
   * 会自动忽略，除非进行了修改
   */
  isTuoMin?: boolean;

  ui?: U;
  /**
   * 定义属性
   */
  properties?: {
    [key: string]: SFSchema<U>;
  };
}

export interface InputUI extends SFUISchemaItem<TChange<string>> {
  /**
   * 最大文本长度
   */
  maxLength?: number;
  /**
   * 最小文本长度
   */
  minLength?: number;
  /**
   * 默认提示语
   */
  placeholder?: string;
  /**
   * 前缀ICON
   */
  prefixIcon?: string | Component;
  /**
   * 后缀ICON
   */
  suffixicon?: string | Component;
  /**
   * 是否是密码框
   */
  showPassword?: boolean;
  /**
   * 如果是密码是否验证
   */
  vaildPassword?: boolean;
  /**
   *是否展示清除ICON
   */
  clearable?: boolean;
}

export interface TextAreaUI extends SFUISchemaItem<TChange<string>> {
  /**
   * 最大文本长度
   */
  maxLength?: number;
  /**
   * 最小文本长度
   */
  minLength?: number;
  /**
   * 默认提示语
   */
  placeholder?: string;
  /**
   *输入框行数
   */
  rows?: number;
  /**
   * textarea 高度是否自适应
   */
  autosize?: boolean;
}
export interface InputNumberUI extends SFUISchemaItem<TChange<number>> {
  /**
   * 最小值
   */
  min?: number;
  /**
   * 最大值
   */
  max?: number;
  /**
   * 计数器步长
   */
  step?: number;
  /**
   * 小数点精度
   */
  precision?: number;
  /**
   * 是否显示控制按钮
   */
  controls?: boolean;
  /**
   * 控制按钮位置
   */
  controlsPosition?: "" | "right";
}
export interface SwitchUI
  extends SFUISchemaItem<TChange<string | boolean | number>> {
  /**
   * 是否显示加载中
   */
  loading?: boolean;
  /**
   * switch 状态为 on 时所显示图标，设置此项会忽略 active-text
   */
  activeIcon?: string | Component;
  /**
   * switch 状态为 off 时所显示图标，设置此项会忽略 inactive-text
   */
  inactiveIcon?: string | Component;
  /**
   * on状态下显示的图标组件
   */
  activeActionIcon?: string | Component;
  /**
   * off状态下显示的图标组件
   */
  inactiveActionIcon?: string | Component;
  /**
   * switch 打开时的文字描述
   */
  activeText?: string;
  /**
   * switch 的状态为 off 时的文字描述
   */
  inactiveText?: string;
  /**
   * switch 打开时的值
   */
  activeValue?: boolean | number | string;
  /**
   * switch 的状态为 off 时的值
   */
  inactiveValue?: boolean | number | string;
  /**
   * 无论图标或文本是否显示在点内，只会呈现文本的第一个字符
   */
  inlinePrompt?: boolean;
}

export interface RadioUI
  extends SFUISchemaItem<TChange<string | boolean | number>> {
  /**
   * 按钮形式的 Radio 激活时的文本颜色
   */
  textColor?: string;
  /**
   *按钮形式的 Radio 激活时的填充色和边框色
   */
  fill?: string;
  /**
   * 是否显示边框
   */
  border?: boolean;

  /**
   * radio 显示模式，button或者radio
   */
  moda: "button" | "radio";

  /**
   * Radio 枚举类型
   */
  items: ItemsEnum[] | (() => Promise<ItemsEnum[]>) | (() => ItemsEnum[]);
}

export interface RateUI extends SFUISchemaItem<TChange<number>> {
  /**
   * 最大分值
   */
  max?: number;
  /**
   * 是否允许半选
   */
  allowHalf?: boolean;
  /**
   * icon 的颜色。 若传入数组，共有 3 个元素，为 3 个分段所对应的颜色；若传入对象，可自定义分段，键名为分段的界限值，键值为对应的颜色
   */
  colors?: string[] | Record<number, string>;
  /**
   *未选中 icon 的颜色
   */
  voidColor?: string;
  /**
   *只读时未选中 icon 的颜色
   */
  disabledVoidColor?: string;
  /**
   * 是否显示辅助文字，若为真，则会从 texts 数组中选取当前分数对应的文字内容
   */
  showText?: boolean;
  /**
   * 是否显示当前分数， show-score 和 show-text 不能同时为真
   */
  showScore?: boolean;
  /**
   * 图标组件 若传入数组，则需要传入 3 个元素，分别为 3 个部分所对应的类名；若传入对象，则可自定义分段，键名为分段的界限值，键值为对应的类名
   */
  icons?: string[] | Component[] | Record<number, string | Component>;
  /**
   *辅助文字的颜色
   */
  textColor?: string;
  /**
   *辅助文和分值一一对应
   */
  texts?: string[];
  /**
   *分数显示模板 采用如何格式'{value}XXXX'
   *模板为一个包含了 {value} 的字符串，{value} 会被替换为当前分值
   */
  scoreTemplate?: string;
}

export interface SelectUI extends SFUISchemaItem<TChange<NzSafeAny>> {
  /**
   * 是否多选
   */
  multiple?: boolean;
  /**
   *multiple 属性设置为 true 时，代表多选场景下用户最多可以选择的项目数， 为 0 则不限制
   */
  multipleLimit?: number;
  /**
   * 作为 value 唯一标识的键名，绑定值为对象类型时必填
   */
  valueKey?: string;
  /**
   * 	是否可以清空选项
   */
  clearable?: boolean;
  /**
   *多选时是否将选中值按文字的形式展示
   */
  collapseTags?: boolean;
  /**
   *多选时是否将选中值按文字的形式展示的最大数量
   */
  maxCollapseTags?: number;

  /**
   * 是否启用分组模式，默认不启动
   */
  enabledGroup?: boolean;
  /**
   * select 枚举类型
   */
  items:
    | ItemsEnum
    | (() => Promise<ItemsEnum[]>)
    | (() => ItemsEnum[])
    | SelectEnum[]
    | (() => Promise<ItemsEnum[]>)
    | (() => SelectEnum[]);

  /**
   * 是否远程加载数据（优先级高于items）
   */
  remote?: boolean;
  /** 远程搜索回调函数，只有当remote=true 有效 */
  remoteMethod?: (
    val: string
  ) => ItemsEnum | Promise<ItemsEnum[]> | SelectEnum[] | Promise<SelectEnum[]>;
}
export interface CascaderUI extends SFUISchemaItem<TChange<CascaderValue>> {
  /**
   * 是否支持清空选项
   */
  clearable?: boolean;
  /**
   * 输入框中是否显示选中值的完整路径
   */
  showAllLevels?: boolean;
  /**
   * 多选模式下是否折叠Tag
   */
  collapseTags?: boolean;
  /**
   * 可搜索
   */
  filterable?: boolean;
  /**
   *用于分隔选项的字符
   */
  separator?: string;
  /**
   *需要显示的 Tag 的最大数量 只有当 collapse-tags 设置为 true 时才会生效。
   */
  maxCollapseTags?: number;
  /**
   * 次级菜单的展开方式
   */
  expandTrigger?: "click" | "hover";
  /**
   * 是否多选
   */
  multiple?: boolean;
  /**
   * 是否严格的遵守父子节点不互相关联
   */
  checkStrictly?: boolean;
  /**
   *在选中节点改变时，是否返回由该节点所在的各级菜单的值所组成的数组，若设置 false，则只返回该节点的值
   */
  emitPath?: boolean;
  /**
   * cascader 枚举类型
   */
  items:
    | CascaderEnum
    | (() => Promise<CascaderEnum[]>)
    | (() => CascaderEnum[]);

  value?: string;
  label?: string;
  leaf?: string;
  propDisabled?: string;
  /**
   * 懒加载
   */
  lazy?: boolean;
  /**
   * 懒加载回调函数
   */
  lazyload: <T>(value: T) => CascaderEnum[] | Promise<CascaderEnum[]>;
}

export interface CheckBoxUI
  extends SFUISchemaItem<TChange<string[] | number[]>> {
  /**
   * 最大可选数量
   */
  max?: number;
  /**
   * 最小可选数量
   */
  min?: number;
  /**
   * 按钮形式的 checkbox 激活时的文本颜色
   */
  textColor?: string;
  /**
   *按钮形式的 Radio 激活时的填充色和边框色
   */
  fill?: string;
  /**
   * 是否显示边框
   */
  border?: boolean;

  /**
   * checkbox 显示模式，button或者radio
   */
  moda: "button" | "checkbox";

  /**
   * checkbox 枚举类型
   */
  items:
    | CheckBoxEnum[]
    | (() => CheckBoxEnum[])
    | (() => Promise<CheckBoxEnum[]>);
}
export interface SliderUI extends SFUISchemaItem<TChange<number>> {
  /**
   * 最大可选数量
   */
  max?: number;
  /**
   * 最小可选数量
   */
  min?: number;
  /**
   * 步长
   */
  step?: number;
  /**
   *是否显示输入框，仅在非范围选择时有效
   */
  showInput?: boolean;
  /**
   * 在显示输入框的情况下，是否显示输入框的控制按钮
   */
  showInputControls?: boolean;

  /**
   * 是否显示间断点
   */
  showStops?: boolean;
  /**
   * 是否显示提示信息
   */
  showTooltip?: boolean;
  /**
   * 是否开启选择范围
   */
  range?: boolean;
  /**
   * 垂直模式
   */
  vertical?: boolean;
  /**
   * 滑块高度，垂直模式必填
   */
  height?: string;
  /**
   * 标记， key 的类型必须为 number 且取值在闭区间 [min, max] 内，每个标记可以单独设置样式
   */
  marks?: Record<number, Mark | string>;

  placement?:
    | "top"
    | "top-start"
    | "top-end"
    | "bottom"
    | "bottom-start"
    | "bottom-end"
    | "left"
    | "left-start"
    | "left-end"
    | "right"
    | "right-start"
    | "right-end";
}

export interface ColorPickerUI extends SFUISchemaItem<TChange<string>> {
  /**
   * 是否支持透明度选择
   */
  showAlpha?: boolean;
  /**
   * 写入 v-model 的颜色的格式
   * 'hex' (when show-alpha is false)
   * 'rgb' (when show-alpha is true)
   */
  colorFormat?: "hsl" | "hsv" | "hex" | "rgb" | "hex" | "rgb";
  /**
   * 步长
   */
  popperClass?: string;
  /**
   *预定义颜色
   */
  predefine?: string[];
}

export interface DateUI extends SFUISchemaItem<TChange<Date | Date[]>> {
  /**
   * 文本框可输入
   */
  editable?: boolean;
  /**
   * 是否显示清除按钮
   */
  clearable?: boolean;
  /**
   * 范围选择时开始日期的占位内容
   */
  startPlaceholder?: string;
  /**
   * 范围选择时结束日期的占位内容
   */
  endPlaceholder?: string;
  /**
   * 是否使用箭头进行时间选择
   */
  arrowControl?: boolean;
  /**
   * 显示类型
   */
  type?:
    | "year"
    | "month"
    | "date"
    | "dates"
    | "datetime"
    | "week"
    | "datetimerange"
    | "daterange"
    | "monthrange";

  /**
   * 显示在输入框中的格式
   * YYYY-MM-DD HH:mm:ss
   */
  format?: string;
  /**
   * DateTimePicker 下拉框的类名
   */
  popperClass?: string;
  /**
   * 选择范围时的分隔符
   */
  rangeSeparator?: string;
  /**
   * 可选，选择器打开时默认显示的时间
   */
  defaultValue?: Date | [Date, Date];
  /**
   * 选择日期后的默认时间值。 如未指定则默认时间值为 00:00:00
   */
  defaultTime?: Date | [Date, Date];
}

export interface UploadUI
  extends SFUISchemaItem<
    (
      response: NzSafeAny,
      uploadFile: UploadFile,
      uploadFiles: UploadFiles
    ) => void
  > {
  /**
   * 上传按钮文字
   */
  text?: string;
  /**
   * 提示说明文字
   */
  tip?: string;
  /**
   * tip 的样式class
   */
  tipClass?: string;
  /**
   * 请求 URL
   */
  action?: string;
  /**
   * 设置上传的请求头部
   */
  headers?: Record<string, NzSafeAny>;
  /**
   * 是否支持多选文件
   */
  multiple?: boolean;
  /**
   * 上传的文件字段名 默认file
   */
  name?: string;
  /**
   * 是否显示已上传文件列表
   */
  showFileList?: boolean;
  /**
   * 是否启用拖拽上传
   */
  drag?: boolean;

  /**
   * 接受上传的文件类型（thumbnail-mode 模式下此参数无效）
   */
  accept?: string;
  /**
   * 点击文件列表中已上传的文件时的钩子
   */
  onPreview?: (uploadFile: UploadFile) => void;
  /**
   * 文件列表移除文件时的钩
   */
  onRemove?: (uploadFile: UploadFile, uploadFiles: UploadFiles) => void;
  /**
   * 文件上传失败时的钩子
   */
  onError?: (
    error: Error,
    uploadFile: UploadFile,
    uploadFiles: UploadFiles
  ) => void;
  /**
   * 文件状态改变时的钩子，添加文件、上传成功和上传失败时都会被调用
   */
  onChange?: (uploadFile: UploadFile, uploadFiles: UploadFiles) => void;
  /**
   * 文件状态改变时的钩子，添加文件、上传成功和上传失败时都会被调用
   */
  beforeUpload?: (
    rawFile: UploadRawFile
  ) => Awaitable<void | undefined | null | boolean | File | Blob>;
  /**
   * 删除文件之前的钩子，参数为上传的文件和文件列表， 若返回 false 或者返回 Promise 且被 reject，则停止删除。
   */
  beforeRemove?: (
    uploadFile: UploadFile,
    uploadFiles: UploadFiles
  ) => Awaitable<boolean>;

  /**
   * 文件列表的类型
   */
  listType?: "text" | "picture" | "picture-card";

  /**
   * 是否自动上传文件
   */
  autoUpload?: boolean;

  /**
   * 允许上传文件的最大数量
   */
  limit?: number;
  /**
   * 覆盖默认的 Xhr 行为，允许自行实现上传文件的请求
   */
  httpRequest?: (
    options: UploadRequestOptions
  ) => XMLHttpRequest | Promise<unknown>;
}

export interface ObjectUI
  extends SFUISchemaItem<TChange<Record<string, NzSafeAny>>> {
  /**
   * 对象展示模式
   */
  moda?: "card" | "collapse";
  /**
   * 	body 的 CSS 样式
   */
  bodyStyle?: CSSProperties;
  /**
   * 是否展现右边button
   */
  showButton?: boolean;
  /**
   *右边button 文字
   */
  buttonText?: string;
  /**
   *右边button class
   */
  buttonClass?: string;
}
